package pay.portal;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.client.RestTemplate;
import org.springframework.amqp.core.Message;

import pay.common.ConstantFYJZH;
import pay.common.ConstantOrderStatus;
import pay.common.ConstantPayment;
import pay.common.ConstantProduct;
import pay.entity.*;
import pay.portal.web.message.PaybackOrderMsg;
import pay.service.*;
import pay.service.sys.ISysUser;
import pay.utils.*;

/**
 * 金账户回款
 *
 * @author 华康
 *
 */
@Controller
@EnableAutoConfiguration
public class PayBackScheduler {
	protected Logger logger = LoggerFactory.getLogger(this.getClass().getName());

	@Autowired
	private IOrderHelper orderHelperService;
	@Autowired
	private IOrderJpa orderJpa;	
	@Autowired
	private IPayBack paybackService;	
	@Autowired
	private IProduct productJPA;	
	
	@Autowired
	private ITrade tradeService;	
	@Autowired
	private ISysUser sysuserService;
	
	@Autowired
	private ISysMsgPassJPA msgService;
	
	@Autowired
	private RestTemplate template;
	
	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Autowired
	private IMessageService messageService;
	
	@Value("${fy.mchntCd}")
	private String mchnt_cd;	
	@Value("${fy.mchntCdLoginId}")
	private String mchntCdLoginId;
	@Value("${fy.goldAccount.pathBaseUrl}")
	private String pathBaseUrl;// 测试环境为/jzh 生产无。	
	@Value("${fy.goldAccount.baseUrl}")
	private String jzhBaseUrl;
	@Value("${msg.host}")
	private String msgHostUrl;
	
    public static final String POUNDAGE_QUEUE = "poundage_queue";
    
	@RabbitListener(queues = POUNDAGE_QUEUE, containerFactory = "rabbitListenerContainerFactory")
    public void handler(String productIdStr) {
//        byte[] body = msg.getBody();
//        String productIdStr = new String(body);
        logger.info("待回款划拨的productId={}",productIdStr);
        if(StringHelper.isEmpty(productIdStr)){
        	errorProcess(null,"金账户回款失败!待回款划拨产品id为空!", productIdStr,null,null);
        	return;
        }
        try {
			Long productId=Long.valueOf(productIdStr);
			ProductInfo productInfo=productJPA.findById(productId);
			if(productInfo==null){
	        	errorProcess(null,"金账户回款失败!不存在此回款划拨产品!", productIdStr,null,null);
		        return;
			}
			
			String creditorPhoneNum=productInfo.getCreditorPhoneNum();//债权人手机号码
			BigDecimal allRaiseAmount=productInfo.getFinancingAccount();//融资金额
			//需要查询债权人余额是否够还款和手续费，需要查询产品的已募集额度
				
			/****************************手续费划拨（每笔总额的千分之2，按照目前回款直接是一笔了，充值总额为募集总额）和提现手续费（2元）***************************/		
			if(StringHelper.isEmpty(creditorPhoneNum)||allRaiseAmount==null){
	        	errorProcess(productInfo,"金账户回款失败!债权人手机号码或融资金额为空，不能回款!", productIdStr,null,null);
				return;
			}
			SysUser creditor=sysuserService.getByPhoneNum(creditorPhoneNum);
			if(creditor==null){
	        	errorProcess(productInfo,"金账户回款失败!债权人不存在，不能回款!", productIdStr,"creditorPhoneNum",creditorPhoneNum);
				return;
			}
			int virtualAccount=creditor.getHasVirtualAccount();
			if(virtualAccount==0){//未开通金账户，不能回款
	        	errorProcess(productInfo,"金账户回款失败!债权人未开通金账户，不能回款!", productIdStr,"creditorPhoneNum",creditorPhoneNum);
				return;
			}
			BigDecimal creditorLeftMoney=sysuserService.getUserLeftMoney(creditor).multiply(BigDecimal.valueOf(0.01));//获取债权人金账户余额
						
			String qryOrderMoneySql="select sum(payBackAmt) from t_order_info where productId="+productId+" and payStatus="+ConstantOrderStatus.PAY_STATUS_TRUE+" and confirmStatus="+ConstantOrderStatus.CONFIRM_STATUS__TRUE+" and paymentId="+ConstantPayment.FYJZH_PAY;
			BigDecimal allPayBackAmt=jdbcTemplate.queryForObject(qryOrderMoneySql, BigDecimal.class);

			BigDecimal allFee=allPayBackAmt.multiply(BigDecimal.valueOf(0.002)).setScale(2,BigDecimal.ROUND_HALF_UP);//客户本息金额的0.2%手续费
			if(productInfo.getCreditorType()!=null && productInfo.getCreditorType() ==1){ // 企业的手续费是回款的时候手动输入的
				allFee = productInfo.getRepayPoundage();
			}


            BigDecimal minAmount=allPayBackAmt.add(allFee);//债权人待回款最低余额
			
			if(creditorLeftMoney.compareTo(minAmount)==-1){//金账户剩余的钱小于最低限额
				String errorMsg="债权人金账户剩余资产小于待回款最低限额，不能扣款!";
				logger.info(errorMsg+"productId={},creditorPhoneNum={},creditorLeftMoney={},minAmount={}",productId,creditorPhoneNum,creditorLeftMoney,minAmount);
				sendMsg(productInfo,productIdStr,errorMsg);
				return;
			}
			boolean ifSuccess=true;
			//out_cust_no付款; in_cust_no:收款方
			boolean transFeeResult=true;
			if(allFee.compareTo(BigDecimal.valueOf(0))==1){//手续费>0
				if(productInfo.getIsPayedFee()==1){//已扣除手续费，不能继续扣
					logger.info("债权人该产品已扣除手续费,直接进行回款!productId={},creditorPhoneNum={}",productId,creditorPhoneNum);	
				}else{
					try {
						transFeeResult=transferAccounts(productInfo, creditorPhoneNum, mchntCdLoginId,allFee);
					} catch (Exception e) {
						ifSuccess=false;
						transFeeResult=false;
			        	errorProcess(productInfo,"金账户回款失败!扣除债权人手续费异常!", productIdStr,"creditorPhoneNum",creditorPhoneNum);
						logger.error("<----------------------------------error------------------------------------->",e);	
					}
				}
			}else{
				logger.info("债权人该产品手续费为0,直接进行回款!productId={},creditorPhoneNum={},allFee={}",productId,creditorPhoneNum,allFee);	
				productInfo.setIsPayedFee(1);
				productJPA.save(productInfo);
			}

			List<Long> userIds = new ArrayList<>();
			List<String> payBackAmtList = new ArrayList<>();

			//paybackamt
			if(transFeeResult){
			//if(true){
				//手续费转账成功，给客户划拨
				List<Map<String, Object>> payBackOrders=orderHelperService.getPayBackOrders(productIdStr);

				if(payBackOrders.size()>0){
					//开始客户回款
					boolean ifChangeProStatus=true;					
					for(Map<String, Object> map:payBackOrders){
						Long orderId=(Long) map.get("id");
						Long userId=(Long) map.get("userId");							
						String userPhone=(String) map.get("Name");
						String contract_no=(String) map.get("contract_no");
						BigDecimal payBackAmt=BigDecimal.valueOf(Double.valueOf(String.valueOf(map.get("payBackAmt")))).setScale(2,BigDecimal.ROUND_HALF_UP);
						boolean custResult=transferToCustomers( productInfo, creditorPhoneNum,  userPhone,
								payBackAmt,orderId,userId,contract_no);
						if(!custResult){	
							logger.info("回款给客户划拨失败!orderId={},userPhone={}",orderId,userPhone);
							ifChangeProStatus=false;
							ifSuccess=false;
						}
						userIds.add(userId);
						payBackAmtList.add(String.valueOf(payBackAmt));
					}										
					//回款完毕更新产品相关信息。
					if(ifChangeProStatus){//只有完全回款成功才更新产品信息
						productInfo.setPayBackStatus(ConstantProduct.PRODUCT_PAYBACK_STATUS_TRUE);					
						productJPA.save(productInfo);
					}					
				}					
			}else{
	        	errorProcess(productInfo,"金账户回款失败!扣除债权人手续费异常!", productIdStr,"creditorPhoneNum",creditorPhoneNum);
	        	ifSuccess=false;
			}	
			if(ifSuccess){
				errorProcess( productInfo, "金账户回款成功!", productIdStr,null,null);
				//回款短信模板
				addToSuccMsgArray(productInfo);
				addToSuccPushMsgArray(userIds, productInfo, payBackAmtList);
			}else{
				errorProcess( productInfo, "金账户回款失败!给客户划拨失败", productIdStr,null,null);

			}
		} catch (Exception e) {
        	errorProcess(null,"金账户回款失败!待回款划拨产品异常!", productIdStr,null,null);
	        logger.error("<----------------------------------error------------------------------------->",e);
		}       
    }

	private void addToSuccPushMsgArray(List<Long> userIds, ProductInfo productInfo, List<String> payBackAmtList) {
		for (int index = 0; index < userIds.size(); index++) {
			Long userId = userIds.get(index);
			String payBackAmt = payBackAmtList.get(index);

			String message = String.format("您购买的%s已成功回款到您的余额账户，回款本息%s元，请到投资资产中查看", productInfo.getName(), payBackAmt);
			this.messageService.sendMsg(String.valueOf(userId), message, "回款通知", ConstantPush.PAYBACK, MsgTypeConstants.PAYBACK);
		}
	}

	private void addToSuccMsgArray(ProductInfo productInfo){
		String orderSql="select distinct s.Name from SysUser s,t_order_info o where o.userId=s.Id and o.productId=?";
		try {
			List<String> phoneList=jdbcTemplate.queryForList(orderSql, new Object [] {productInfo.getId()},String.class);
			String phoneListStr = String.join(",", (String[])phoneList.toArray(new String[phoneList.size()]));
			sendtoAllMsg(productInfo.getName(), phoneListStr);
		} catch (Exception e) {
			logger.info("回款短信群发给客户异常!productId={}",productInfo.getId());
			logger.error("<---------------------------ERROR------------------------->",e);
		}
		
		
	}
	private void sendtoAllMsg(String productName,String phoneArrayStr){
		/*尊敬的用户，您购买的久恒福海（180天）002产品已成功回款至您的余额账户，请登录华财通查看，如有疑问请致电客服4001021010*/
		StringBuilder content=new StringBuilder("尊敬的用户，您购买的").append(productName).append("产品已成功回款至您的余额账户，请登录华财通查看，如有疑问请致电客服4001021010");		
		MsgUtils.sendMsg(template,content.toString(), phoneArrayStr);			
	}
	
	private void errorProcess(ProductInfo productInfo,String errorMsg,String productId,String keyName2,String keyValue2){
		if(StringHelper.isNotEmpty(keyName2)){
			logger.info(errorMsg+"productId={},"+keyName2+"={}",productId,keyValue2);
		}else{
			logger.info(errorMsg+"productId={}",productId);
		}
		try {
			sendMsg(productInfo,productId,errorMsg);
		} catch (Exception e) {
			logger.info("回款发送短信异常!productId={}",productId);
			logger.error("<----------------------------------error------------------------------------->",e);
		}
		
	}
		
	
	private void sendMsg(ProductInfo productInfo,String productId,String errorMsg){
		String content;
		if(productInfo!=null){
			content=errorMsg+"productId="+productInfo.getId()+"产品名称="+productInfo.getName();
		}else{
		    content=errorMsg+"productId="+productId;
		}
		SendMsgPass msgPass =msgService.findById(3L);
		String userIds=msgPass.getDescription();
		String[] userList=userIds.split(",");
		for(String currentUserId:userList){
			if(StringHelper.isNotEmpty(currentUserId)){
				Long userIdLong=Long.parseLong(currentUserId);
				SysUser user=sysuserService.findById(userIdLong);
				if(user!=null){	
					String phone=user.getName();
					MsgUtils.sendMsg(template,content, phone);		
				}
			}
		}
	}
	private boolean transferToCustomers(ProductInfo productInfo, String out_cust_no, String in_cust_no,
										BigDecimal amt, Long orderId, Long userId, String contract_no){
		boolean result=true;
		Long productId=productInfo.getId();
		Long cts=System.currentTimeMillis();
		String mchnt_txn_ssn=cts+in_cust_no;
		String rpcResult= transToCustomer( productId, out_cust_no,  in_cust_no,
				 amt, mchnt_txn_ssn);
		if ("-1111".equals(rpcResult)) {
			logger.info("划拨--债权人回款给客户富友调用异常！,mchnt_txn_ssn={},productId={},out_cust_no={},in_cust_no={}",
					mchnt_txn_ssn,productId, out_cust_no, in_cust_no);
			result=false;
		} else {
			 String resp_code = XmlUtils.getVal(rpcResult, "resp_code");
			 /**************************写回款信息文件**************************/
			 try {
				paybackService.writeProductFile(resp_code, orderId, in_cust_no, out_cust_no, amt, userId, productId);
			 } catch (Exception e) {
				logger.error("写回款信息文件失败！", e);
			 }
			 /**************************写回款表到数据库**************************/
			 try {
				 addToTrade( out_cust_no,  in_cust_no,
							 amt, orderId, userId, contract_no, cts, mchnt_txn_ssn, productId, resp_code,"回款");
			 } catch (Exception e) {
					logger.error("写回款表到数据库失败！", e);
			 }
			 
			if ("0000".equals(resp_code)) {			
				 /**************************更新客户信息**************************/
				OrderInfo orderInfo=orderJpa.findById(orderId);
				orderInfo.setPayStatus(ConstantOrderStatus.PAY_STATUS_PAYBACK);
				orderInfo.setConfirmStatus(ConstantOrderStatus.CONFIRM_STATUS__PAYBACK);				
				orderHelperService.updateOrder(orderInfo);
			} else {
				logger.info(
						"划拨--债权人回款给客户富友失败！失败的响应码resp_code={},productId={},mchnt_txn_ssn={}",
						resp_code, productId,mchnt_txn_ssn);
				result=false;
			}
		}
		return result;
	}
	private void addToTrade(String out_cust_no, String in_cust_no,
			BigDecimal amt,Long orderId,Long userId,String contract_no,Long cts,String mchnt_txn_ssn,Long productId,String resp_code,String tradeType){
		Trade trade=new Trade();
		trade.setAmt(amt);
		trade.setContract_no(contract_no);
		trade.setCts(cts);
		trade.setFlowType(ConstantFYJZH.BALANCE_ADD);
		trade.setLogin_id(in_cust_no);
		trade.setMchnt_txn_ssn(mchnt_txn_ssn);
		trade.setOrderId(orderId);
		trade.setProductId(productId);
		trade.setResp_code(resp_code);
		trade.setTradeDesc(tradeType);
		trade.setType(ConstantFYJZH.TRADE_TY_HK);
		trade.setUserId(userId);
		tradeService.save(trade);
	}
	private boolean transferAccounts(ProductInfo productInfo,String out_cust_no, String in_cust_no,
			BigDecimal amt){//out_cust_no 付款方；in_cust_no：入账方
		boolean result=true;	
		Long productId=productInfo.getId();
		Long cts=System.currentTimeMillis();
		String mchnt_txn_ssn=""+cts+productId;
		String rpcResult=transFee( productId, out_cust_no,  in_cust_no,
				 amt,mchnt_txn_ssn);
		if ("-1111".equals(rpcResult)) {
			logger.info("转账--债权人手续费rpc调用异常！,mchnt_txn_ssn={},productId={},out_cust_no={},in_cust_no={}",
					mchnt_txn_ssn,productId, out_cust_no, in_cust_no);
			result=false;
		} else {
			 String resp_code = XmlUtils.getVal(rpcResult, "resp_code");
			 try {
				 paybackService.writeProductFile(resp_code, null, in_cust_no, out_cust_no, amt, null, productId);
				 } catch (Exception e) {
					logger.error("写手续费信息文件失败！", e);
				 }	
			 /**************************写手续费到数据库**************************/
			 try {
				 addToTrade( out_cust_no,  in_cust_no,
							 amt, null, null, null, cts, mchnt_txn_ssn, productId, resp_code,"债权人手续费转账");
			 } catch (Exception e) {
					logger.error("写手续费到数据库失败！", e);
			 }
			if ("0000".equals(resp_code)) {//转账手续费成功		
				productInfo.setIsPayedFee(1);
				productJPA.save(productInfo);
			} else {
				logger.info(
						"转账--债权人手续费失败！失败的响应码resp_code={},productId={},mchnt_txn_ssn={}",
						resp_code, productId,mchnt_txn_ssn);
				result=false;
			}
		}
		return result;
	}
	
	
	private String transFee(Long productId,String out_cust_no, String in_cust_no,
			BigDecimal amt,String mchnt_txn_ssn) {//手续费转账到华康总虚账
		Map<String, String> map = new HashMap<String, String>();
		//out_cust_no付款; in_cust_no:收款方
		//amt + "|" +contract_no+"|"+in_cust_no+"|"+ mchnt_cd + "|" + mchnt_txn_ssn+"|"+ out_cust_no +"|"+ rem;		
		map.put("mchnt_cd", mchnt_cd);
		map.put("mchnt_txn_ssn", mchnt_txn_ssn);
		map.put("out_cust_no", out_cust_no);
		map.put("in_cust_no", in_cust_no);
		map.put("contract_no", "");
		map.put("rem", "");
		map.put("amt", ""+amt.multiply(BigDecimal.valueOf(100)).intValue());//以分为单位
		map = MapSortUtil.sortMapByKey(map);
		String pathUrl = pathBaseUrl + "/transferBmu.action";
		logger.info("转账url={}",pathUrl);
		return FYApiUtil.sendPostToFYUtils(map, jzhBaseUrl, pathUrl);
	}
    
    private String transToCustomer(Long productId,String out_cust_no, String in_cust_no,
			BigDecimal amt,String mchnt_txn_ssn) {//本息划拨给客户
		Map<String, String> map = new HashMap<String, String>();
		//out_cust_no付款; in_cust_no:收款方
		//amt + "|" +contract_no+"|"+in_cust_no+"|"+ mchnt_cd + "|" + mchnt_txn_ssn+"|"+ out_cust_no +"|"+ rem;
		String allUrl=amt + "|" +""        +"|"+mchnt_cd+"|"+ mchnt_cd + "|" + mchnt_txn_ssn+"|"+ out_cust_no +"|"+ "";
		logger.info("富友划拨接口入参明文={}" ,allUrl);
		map.put("mchnt_cd", mchnt_cd);
		map.put("mchnt_txn_ssn", mchnt_txn_ssn);
		map.put("out_cust_no", out_cust_no);
		map.put("in_cust_no", in_cust_no);		
		map.put("amt", ""+amt.multiply(BigDecimal.valueOf(100)).intValue());//以分为单位
		map.put("contract_no", "");		
		map.put("rem", "");
		map = MapSortUtil.sortMapByKey(map);
		String pathUrl = pathBaseUrl + "/transferBu.action";
		return FYApiUtil.sendPostToFYUtils(map, jzhBaseUrl, pathUrl);
	}
	
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
	
	//@Scheduled(cron = "0 0/1 * * * ?")
	public void testTasks() {
		logger.info("查询回款定时任务开始……");
		Executor executor = Executors.newFixedThreadPool(1);
		Runnable task = new Runnable() {
			public void run() {
				payBackToUserTask();
				logger.info("查询回款定时任务结束……");
			}
		};
		executor.execute(task);

	}

	/**
	 * 金账户回款
	 *
	 * @param
	 */
	public void payBackToUserTask() {

		List<String> paybackOrderList = orderHelperService.getPaybackOrderListFromRedis();


		if (paybackOrderList != null &&  paybackOrderList.size() > 0){
			logger.info("开始回款划拨， 待回款的记录总数是： size ={}", paybackOrderList.size());
		}else{
			logger.info("开始回款划拨， 待回款的记录总数是：0,操作停止");
			return ;
		}

		for(String paybackOrderMsgStr: paybackOrderList ){

			PaybackOrderMsg paybackOrderMsg = JsonUtils.toBean(paybackOrderMsgStr, PaybackOrderMsg.class);

			Long orderId = paybackOrderMsg.getOrderId();


			String mchnt_txn_ssn = paybackService.getSSN(orderId);

			//将需要回款的订单信息先保存在redis中
			paybackService.addPaybackRecordIntoRedis(mchnt_txn_ssn, paybackOrderMsgStr);

			//获取回款结果
			Boolean result = paybackService.payBack(mchnt_txn_ssn);

			logger.info("回款划拨结果是 result={}, orderId={}", result, orderId);
		}
	}


}



